﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WorkStation.Frameworks.EasyBus.Pipeline.Filters;
using WorkStation.Frameworks.EasyBus.Pipeline.Handles;

namespace WorkStation.Frameworks.EasyBus.Pipeline.Modules
{
    /// <summary>
    /// 处理模块
    /// </summary>
    public class Module : IModule
    {
        #region 公有属性

        /// <summary>
        /// 处理对象类型全名
        /// </summary>
        public string ProcessType { get; set; }

        /// <summary>
        /// 处理器
        /// </summary>
        public Dictionary<string, IHandle> Handles { get; set; }

        /// <summary>
        /// 顺序
        /// </summary>
        public int Order { get; set; }

        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="processType">处理对象类型</param>
        public Module(string processType)
        {
            this.Handles = new Dictionary<string, IHandle>();
            this.ProcessType = processType;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="processType">处理对象类型</param>
        public Module(Type processType) : this(processType.FullName) { }

        #endregion

        #region 公有函数

        /// <summary>
        /// 处理
        /// </summary>
        /// <param name="context">执行上下文</param>
        /// <returns></returns>
        public IEnumerable<HandleResult> Process(ActionContext context)
        {
            List<HandleResult> result = new List<HandleResult>();
            List<Task<HandleResult>> asyncResult = new List<Task<HandleResult>>();

            //string inputType = context.Input.GetType().FullName;

            string routeKey = context.RouteKey;

            if (routeKey.Equals(this.ProcessType) || this.ProcessType.Equals(typeof(object).FullName))
            {
                IEnumerable<IHandle> handles = this.Handles.Select(v => v.Value).OrderBy(v => v.Order).ToArray();

                foreach (IHandle handle in handles)
                {
                    if (!context.IsContinue)
                    {
                        break;
                    }

                    if (handle is AsyncHandle)
                    {
                        asyncResult.Add((handle as AsyncHandle).AsyncExecute(context));
                    }
                    else
                    {
                        result.Add(handle.Execute(context));
                    }
                }

                Task.WaitAll(asyncResult.ToArray());

                asyncResult.ForEach(v => result.Add(v.Result));
            }

            return result;
        }

        /// <summary>
        /// 订阅
        /// </summary>
        /// <param name="handle">处理器对象</param>
        /// <returns></returns>
        public IModule Subscribe(IHandle handle)
        {
            try
            {
                this.Handles.Add(handle.Name, handle);
            }
            catch (ArgumentException ce)
            {
                throw new Exception(string.Format("该处理器名称已经使用, 名称【{0}】", handle.Name));
            }

            return this;
        }

        /// <summary>
        /// 订阅
        /// </summary>
        /// <param name="func">处理内容委托</param>
        /// <param name="handleName">处理器名称</param>
        /// <param name="filter">过滤器</param>
        /// <param name="order">顺序</param>
        /// <returns></returns>
        public IModule Subscribe(Func<ActionContext, IHandle, HandleResult> func, string handleName = null, IFilter filter = null, int order = -1)
        {
            this.Subscribe(new Handle(handleName, filter, order).RegisterHandle(func));

            return this;
        }

        /// <summary>
        /// 异步订阅
        /// </summary>
        /// <param name="func">处理内容委托</param>
        /// <param name="handleName">处理器名称</param>
        /// <param name="filter">过滤器</param>
        /// <returns></returns>
        public IModule AsyncSubscribe(Func<ActionContext, IHandle, HandleResult> func, string handleName = null, IFilter filter = null)
        {
            this.Subscribe(new AsyncHandle(handleName, filter).RegisterHandle(func));

            return this;
        }

        /// <summary>
        /// 退订
        /// </summary>
        /// <param name="handleName">处理器名称</param>
        /// <returns></returns>
        public IModule UnSubscribe(string handleName) 
        {
            this.Handles.Remove(handleName);

            return this;
        }

        #endregion
    }
}
